<template>
  <div class="tree-config">
    <div class="tree-btn">
      <!-- 二级容器只能有一个 不可添加 -->
      <a-button v-if="!(type === 'second' && treeData.length)" type="primary" size="small" @click="handleAdd">
        新增布局容器
      </a-button>
    </div>
    <a-tree
      v-if="treeData.length"
      v-model:selectedKeys="selectedKeys"
      :tree-data="treeData"
      draggable
      show-line
      default-expand-all
      @select="select"
      @drop="onDrop"
    >
      <!-- 标题 -->
      <template #title="{ title, dataRef }">
        <a-dropdown :trigger="['contextmenu']">
          <span>{{ title }}</span>
          <template #overlay>
            <a-menu @click="({ key: menuKey }) => onContextMenuClick(menuKey, dataRef)">
              <a-menu-item key="add">添加组件</a-menu-item>
              <a-menu-item key="del" v-if="type !== 'second'">删除</a-menu-item>
            </a-menu>
          </template>
        </a-dropdown>
      </template>
    </a-tree>

    <!-- 配置 弹框 -->
    <component ref="settingBox" :is="currentComponent" @submit="data => setTreeData(treeData, data)" />
    <!-- 选择组件 -->
    <a-modal v-model:visible="visible" title="选择组件" width="80%" destroyOnClose @ok="handleOk">
      <component-box ref="componentList" isView />
    </a-modal>
  </div>
</template>

<script>
import ComponentBox from '../../component-manage/index.vue'
import ContainerSet from './settings/ContainerSet.vue'
import ComponentSet from './settings/ComponentSet.vue'
/**
 * 页面管理 - 页面配置 - 树结构配置
 * @author 朱琦
 * @date   时间：2023/1/31
 */
const x = 3
const y = 2
const z = 1
const genData = []
const generateData = (_level, _preKey, _tns) => {
  const preKey = _preKey || '0'
  const tns = _tns || genData
  const children = []
  for (let i = 0; i < x; i++) {
    const key = `${preKey}-${i}`
    tns.push({
      title: key,
      key
    })
    if (i < y) {
      children.push(key)
    }
  }
  if (_level < 0) {
    return tns
  }
  const level = _level - 1
  children.forEach((key, index) => {
    tns[index].children = []
    return generateData(level, key, tns[index].children)
  })
}

export default {
  name: 'TreeConfig',
  props: {
    data: {
      type: Object,
      default: () => {
        return {}
      }
    },
    config: {
      type: Object,
      default: () => {
        return {}
      }
    }
  },
  components: {
    ContainerSet,
    ComponentSet,
    ComponentBox
  },
  data() {
    return {
      treeData: [],
      selectedKeys: null,
      visible: false,
      currentComponent: null,
      currentTreeData: {}
    }
  },
  computed: {
    type() {
      return this.config.type
    }
  },
  watch: {
    config: {
      immediate: true,
      deep: true,
      handler() {
        this.treeData = this.config.list || []
      }
    }
  },
  created() {},
  mounted() {},
  methods: {
    /**
     * 获取默认数据 布局容器
     */
    getDefaultData() {
      const data = {
        key: 'container-' + this.type + new Date().getTime(),
        type: this.type, // 容器类型 与页面类型对应
        title: '布局容器' + (this.treeData.length + 1),
        settingType: 'ContainerSet', // 配置类型  和配置组件名对应
        children: []
      }
      return data
    },
    /**
     * 点击新增布局容器
     */
    handleAdd() {
      const data = this.getDefaultData()
      this.treeData.push(data)
      // 同步到vuex
      this.$store.commit('page-manage-config/SET_CONTAINER_LIST', { data, handle: 'add' })
    },
    /**
     * 树节点 点击触发
     * @param {*} selectedKeys
     * @param {*} param1
     */
    select(selectedKeys, { selected, node, selectedNodes }) {
      // 选中时
      if (selected) {
        // 获取配置组件名
        this.currentComponent = node.dataRef.settingType
        this.selectedKeys = []
        this.$nextTick(() => {
          // 显示
          this.$refs.settingBox && this.$refs.settingBox.show(node.dataRef)
        })
      } else {
        // 取消选中
      }
    },
    /**
     * 点击菜单
     * @param {String} menuKey 菜单值
     * @param {Object} data 所选数据
     */
    onContextMenuClick(menuKey, data) {
      this.currentTreeData = data
      if (menuKey === 'add') {
        // 新增组件
        this.visible = true
      } else if (menuKey === 'del') {
        // 删除
        this.setTreeData(this.treeData, data, 'del')
      }
    },
    /**
     * 选择组件 完成
     */
    handleOk() {
      const data = this.$refs.componentList.getSelectData()
      if (!Object.keys(data).length) return this.$message.warning('请勾选组件')
      const item = {
        key: this.type + '-' + new Date().getTime(),
        componentId: data.id,
        title: data.componentName,
        component: data.componentCode, // 组件名
        componentProps: data.componentParams ? JSON.parse(data.componentParams) : null, // 组件的属性
        // routeName: data.componentCode, // 菜单组件对应的路由名
        span: data.componentGridSize, // 子容器的栅格数
        settingType: 'ComponentSet', // 配置类型  和配置组件名对应
        style: null // 子容器样式
      }
      if (!this.currentTreeData.children) {
        this.currentTreeData.children = []
      }
      this.currentTreeData.children.push(item)
      this.visible = false
    },
    /**
     * 操作 树 数据源
     * @param {Array} treeData 列表数据
     * @param {Object} currentTreeData 当前比对数据项
     * @param {String} handle 操作类型
     * @param {Object} handleData 操作数据
     */
    setTreeData(treeData, currentTreeData, handle = 'edit', handleData) {
      treeData.some((item, index) => {
        if (item.constructor !== Object) {
          return false
        } else if (item.key === currentTreeData.key) {
          if (handle === 'edit') {
            // 修改数据
            treeData[index] = { ...item, ...currentTreeData }
          } else if (handle === 'del') {
            // 删除数据
            treeData.splice(index, 1)
            if (currentTreeData.settingType === 'ContainerSet') {
              // 操作布局容器时

              // 同步到vuex
              this.$store.commit('page-manage-config/SET_CONTAINER_LIST', { data: currentTreeData, handle: 'del' })
            }
          } else if (handle === 'add') {
            // 新增 子数据
            if (!treeData.children || treeData.children.constructor !== Array) {
              treeData.children = []
            }
            treeData.children.push(handleData)
          }
          return true
        } else {
          return item.children ? this.setTreeData(item.children, currentTreeData, handle, handleData) : false
        }
      })
    },
    onDrop(info) {
      // node 拖拽的节点最后所处的node 数据
      // dragNode 被拖拽的节点 数据
      console.log(info)
      const dropKey = info.node.key
      const dragKey = info.dragNode.key // 被拖拽的节点
      const dropPos = info.node.pos.split('-') // 节点定位
      const drapPos = info.dragNode.pos.split('-') // 节点定位
      if (info.dragNode.settingType === 'ContainerSet') {
        this.$message.info('不能拖拽布局容器')
        return
      } else if (dropPos.length !== drapPos.legnth) {
        this.$message.info('只能同层级拖拽')
        return
      } else if (dropPos.length > 3 || info.dropPosition < 0) {
        // 层级超过3时不可拖拽
        // 拖拽位置大于 -1
        return
      }
      const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])
      const loop = (data, key, callback) => {
        data.forEach((item, index) => {
          if (item.key === key) {
            return callback(item, index, data)
          }
          if (item.children) {
            return loop(item.children, key, callback)
          }
        })
      }
      const data = [...this.treeData]

      // Find dragObject
      let dragObj
      loop(data, dragKey, (item, index, arr) => {
        arr.splice(index, 1)
        dragObj = item
      })
      if (!info.dropToGap) {
        // 不是拖拽到顶部时
        // Drop on the content
        loop(data, dropKey, item => {
          item.children = item.children || []
          // / where to insert 示例添加到头部，可以是随意位置
          item.children.unshift(dragObj)
        })
      } else if (
        (info.node.children || []).length > 0 &&
        // Has children
        info.node.expanded &&
        // Is expanded
        dropPosition === 1 // On the bottom gap
      ) {
        loop(data, dropKey, item => {
          item.children = item.children || []
          // where to insert 示例添加到头部，可以是随意位置
          item.children.unshift(dragObj)
        })
      } else {
        let ar = []
        let i = 0
        loop(data, dropKey, (_item, index, arr) => {
          ar = arr
          i = index
        })
        if (dropPosition === -1) {
          ar.splice(i, 0, dragObj)
        } else {
          ar.splice(i + 1, 0, dragObj)
        }
      }
    }
  },

  beforeUnmount() {
    // 销毁时 清除当前类型的容器列表
    this.$store.commit('page-manage-config/SET_CONTAINER_LIST', { data: this.type, handle: 'delType' })
  }
}
</script>

<style scoped lang="less">
.tree-config {
  .tree-btn {
    text-align: right;
    .ant-btn {
      margin-left: 10px;
    }
  }
}
</style>
